#include <iostream>
#include <cstdio>
#include <string>

#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "protocol.hpp"
#include "Log.hpp"
#include "Comm.hpp"

using namespace LogModule;
// ./client_tcp server_ip server_port
int main(int argc,char *argv[])
{
	if(argc != 3)
	{
		LOG(LogLevel::ERROR) << "Usage: " << argv[0] << " server_ip server_port";
		return 1;
	}
	std::string server_ip = argv[1];
	int servre_port = std::stoi(argv[2]);
	
	// 创建套接字
	int sockfd = socket(AF_INET,SOCK_STREAM,0);
	if(sockfd < 0)
	{
		LOG(LogLevel::ERROR) << "create socket failed";
		return 2;
	}
	
	
	// 填写网络信息
	struct sockaddr_in server_addr;
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = ::htons(servre_port);
	server_addr.sin_addr.s_addr = ::inet_addr(server_ip.c_str());

	// client 不需要显示的进行bind, tcp是面向连接的, connect 底层会自动进行bind
	int n = connect(sockfd,CONV(&server_addr),sizeof(server_addr));
	if(n < 0)
	{
		LOG(LogLevel::ERROR) << "connect failed";
		return 3;
	}

	// echo client
	std::string message;
	while(true)
	{
		int x,y;
		char oper;
		std::cout << "input x: ";
        std::cin >> x;
        std::cout << "input y: ";
        std::cin >> y;
        std::cout << "input oper: ";
        std::cin >> oper;

		Requst req(x,y,oper);
		req.Print();
		// 序列化
		req.Serialize(message);
		// 添加报头
		AddHander(message);
		// 发送
		int n = ::send(sockfd,message.c_str(),message.size(),0);
		if(n < 0)
		{
			LOG(LogLevel::ERROR) << "write failed";
			break;
		}
		else if(n > 0)
		{
			char buffer[1024];
			// int m = ::read(sockfd,buffer,sizeof(buffer)-1);
			int m = ::recv(sockfd,buffer,sizeof(buffer)-1,0);
			if(m < 0)
			{
				LOG(LogLevel::ERROR) << "read failed";
				break;
			}
			else if(m > 0)
			{
				buffer[m] = 0;
				std::string package = buffer;
				std::string content;
				// 移除报头
				RemoveHander(package,content);
				// 反序列化
				Response res;
				res.Deserialize(content);

				// 6. 得到结构化数据
                std::cout << res.GetResult() << " [" << res.GetCode() << "] " << std::endl;
				
			}
		}
	}
	::close(sockfd);

	return 0;
}